﻿using System.Windows.Data;
using System.Globalization;
using Serilog;
using System.Windows;
using SimpleTool.ActivityUnit;
using System.Reflection;
using System.Collections.Concurrent;
using System.Windows.Media;
using System.Windows.Markup;
using System.Reactive.Linq;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.Collections;

namespace SimpleTool.Server
{

	[ContentProperty("Bindings")]
    public class MultiFunctionalMarkupExtend : MarkupExtension
    {
		public BindingMode Mode { set; get; } = BindingMode.TwoWay;

		public UpdateSourceTrigger SourceTrigger { set; get; } = UpdateSourceTrigger.PropertyChanged;

		public ObservableCollection<BindingBase> Bindings { set; get; } = [];

        public object? ConverterParameter { set; get; } = null;

        public Brush Friendly { set; get; } = "JadeFlow".FindSolidBrush();

        public Brush Unamiable { set; get; } = "CoralRed".FindSolidBrush();

		public bool DoingProvideValue { set; get; } = false;

        public MarkUpExteandType MarkupType { set; get; } = MarkUpExteandType.Yield;

        public MarkUpDisposeType DisposeType { set; get; } = MarkUpDisposeType.Invalid;

        public MarkUpAssistType AssistType { set; get; } = MarkUpAssistType.Invalid;


		//  A[XAML 解析器] --> B[调用您的 ProvideValue]
		//  B --> C[返回 MultiBinding 对象]
		//  C --> D[WPF 绑定系统调用 MultiBinding.ProvideValue]
		//  D --> E[创建最终的绑定表达式]
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Bindings.Count == 1)
            {
                Binding ValidBinding = (Binding)Bindings[0];

				ValidBinding.Mode = Mode;

                ValidBinding.ConverterParameter = ConverterParameter;

                ValidBinding.UpdateSourceTrigger = SourceTrigger;

				ValidBinding.Converter = new MarkupSingleConverter
				{
					MarkupType = MarkupType,
					DisposeType = DisposeType,
					AssistType = AssistType,
					Friendly = Friendly,
					Unamiable = Unamiable
                };

				object Provide = ValidBinding.ProvideValue(serviceProvider);

                if (DoingProvideValue)
                {
                    if (Provide is Freezable _Freezable && _Freezable.CanFreeze)
                    {
						Application.Current.Dispatcher.Invoke(() =>
						{
							_Freezable.Freeze();
						});
                    }
                    return ValidBinding.ProvideValue(serviceProvider);
                }
                else
                {
                    return ValidBinding;
                }
            }
            else
			{
                MultiBinding MultiVaidBinding = new ()
				{
					Mode = Mode,
                    ConverterParameter = ConverterParameter,
                    UpdateSourceTrigger = SourceTrigger,
                    Converter = new MarkupMultiConverter()
					{
						MarkupType = MarkupType,
						DisposeType = DisposeType,
						AssistType = AssistType,
						Friendly = Friendly,
						Unamiable = Unamiable
                    }
                };

				foreach (var bingding in Bindings)
				{
					MultiVaidBinding.Bindings.Add(bingding);
				}

                object Provide = MultiVaidBinding.ProvideValue(serviceProvider);


                if (DoingProvideValue)
				{
                    if (Provide is Freezable _Freezable && _Freezable.CanFreeze)
                    {
						Application.Current.Dispatcher.Invoke(() =>
						{
							_Freezable.Freeze();
						});
                    }
					return Provide;

                }
				else
				{
					return MultiVaidBinding;
				}
            }
        }
    }

    public class MarkupSingleConverter : Freezable, IValueConverter
	{
        private readonly ILogger Logger = Log.ForContext<MarkupSingleConverter>();

        private readonly ConcurrentDictionary<Interfacial, Lazy<FrameworkElement>> _InstanceMap = [];

        public Brush Friendly { set; get; } = "GaoguiZong".FindSolidBrush();

        public Brush Unamiable { set; get; } = "CoralRed".FindSolidBrush();

        public MarkUpExteandType MarkupType { set; get; } = MarkUpExteandType.Yield;

        public MarkUpDisposeType DisposeType { set; get; } = MarkUpDisposeType.Invalid;

        public MarkUpAssistType AssistType { set; get; } = MarkUpAssistType.Invalid;

        private UserControl? ControlElement = null;

        public object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
			if (MarkupType == MarkUpExteandType.UserControl)
			{
				if (value is UIBind _UIBind)
				{
					try
					{
						ControlElement ??= new WaitMinute(_UIBind.IsPlayAnimation);
						CreaterInstance(_UIBind);
						return ControlElement;
					}
					catch (Exception error)
					{
						Logger.Print(RuntimeLog.LogType.Error, $"{MethodBase.GetCurrentMethod()?.Name} Error: {error.Message}");
					}
				}
			}

			else if (MarkupType == MarkUpExteandType.GridLenght)
			{
				if (DisposeType == MarkUpDisposeType.GridLenght)
				{
					bool result = false;

					if (int.TryParse(parameter.GetSafetyChar().Trim(), out int _parameter))
					{
						if (value is string _string)
						{
							result = !string.IsNullOrEmpty(_string);
						}
						else if (value is bool _bool)
						{
							result = _bool;
						}
						else if (value is Visibility _Visibility)
						{
							result = _Visibility == Visibility.Visible;
						}
					}
					if (AssistType == MarkUpAssistType.Lenght)
					{
						return result ? new GridLength(_parameter) : GridLength.Auto;
					}
					else if (AssistType == MarkUpAssistType.Star)
					{
						return result ? new GridLength(_parameter, GridUnitType.Star) : GridLength.Auto;
					}
					else
					{
						return GridLength.Auto;
					}
				}

				else if (DisposeType == MarkUpDisposeType.HireValue)
				{

					if (value is UIBind _UIBind &&
						parameter is string _parameter)
					{
						string[] paramSplit = RegExp.RegExpMultiSpacing().Split(_parameter);
						string type = string.Empty;
						string validvalue = string.Empty;
						if (paramSplit.Length > 1)
						{
							type = paramSplit.ElementAt(0);
							validvalue = paramSplit.ElementAt(1);
						}

						if ($"{_UIBind.UIType}" == type && int.TryParse(validvalue.Trim(), out int _parameter1))
						{
							if (AssistType == MarkUpAssistType.Lenght)
							{
								return new GridLength(_parameter1);
							}
							else if (AssistType == MarkUpAssistType.Star)
							{
								return new GridLength(_parameter1, GridUnitType.Star);
							}
						}
						else
						{
							return GridLength.Auto;
						}
					}
				}
			}

			else if (MarkupType == MarkUpExteandType.Radius)
			{
				if (DisposeType == MarkUpDisposeType.BooladdSub)
				{
					if (value is CornerRadius _CornerRadius)
					{

						if (parameter is not null and string _parameter && !string.IsNullOrEmpty(_parameter))
						{
							List<bool> _params = [.. parameter.GetSafetyChar().MatchAll("[0-9a-zA-Z]+").Values
												  .Where(x=>bool.TryParse(x, out bool _))
												  .Select(x=>bool.Parse(x))];

							return new CornerRadius(_params.ElementAt(0) ? _CornerRadius.TopLeft : 0, _params.ElementAt(1) ? _CornerRadius.TopRight : 0,
													_params.ElementAt(2) ? _CornerRadius.BottomLeft : 0, _params.ElementAt(4) ? _CornerRadius.BottomRight : 0);
						}
					}
				}
			}

			else if (MarkupType == MarkUpExteandType.String)
			{
				if (DisposeType == MarkUpDisposeType.AppendText)
				{
					if (parameter is not null)
					{
						if (AssistType == MarkUpAssistType.Left)
						{
							return parameter.GetSafetyChar() + value.GetSafetyChar();
						}
						else if (AssistType == MarkUpAssistType.Right)
						{
							return value.GetSafetyChar() + parameter.GetSafetyChar();
						}
						else
						{
							if (parameter is string _format && _format.Contains('{') && _format.Contains('}'))
							{
								return string.Format(_format, value);
							}
							else
							{
								return parameter.GetSafetyChar() + value.GetSafetyChar();
							}
						}
					}
					else
					{
						return value;
					}
				}

				else if (DisposeType == MarkUpDisposeType.ValidCheck)
				{
					bool isValid = value.IsAbsoluteValidValue();

					if (isValid)
					{
						return value;
					}
					else
					{
						if (parameter is not null)
						{
							return parameter;
						}
					}
				}
			}

			else if (MarkupType == MarkUpExteandType.Visiblity)
			{
				if (DisposeType == MarkUpDisposeType.ValidCheck)
				{
					bool isValid = value.IsAbsoluteValidValue();

					if (AssistType == MarkUpAssistType.Reversed)
					{
						return !isValid ? Visibility.Visible : Visibility.Collapsed;
					}

					return isValid ? Visibility.Visible : Visibility.Collapsed;
				}
				else if (DisposeType == MarkUpDisposeType.HireValue)
				{

					if (value is UIBind _UIBind)
					{

						if (parameter is string _parameter && $"{_UIBind.UIType}" == _parameter)
						{
							return Visibility.Visible;
						}
						else
						{
							return Visibility.Collapsed;
						}
					}
				}
			}

			else if (MarkupType == MarkUpExteandType.Brush)
			{
				if (DisposeType == MarkUpDisposeType.ValidCheck)
				{
					bool isValid = value.IsAbsoluteValidValue();

					if (AssistType == MarkUpAssistType.Reversed)
					{
						return !isValid ? Friendly : Unamiable;
					}
					return isValid ? Friendly : Unamiable;
				}
				else if (DisposeType == MarkUpDisposeType.Classify)
				{
					if (value is not null and EmbeddedTreeStructure.Identity _Identity)
					{
						Brush _Brush = _Identity switch
						{
							EmbeddedTreeStructure.Identity.Friendly => "ElectricLime".FindSolidBrush(),
							EmbeddedTreeStructure.Identity.Unamiable => "SunsetCoral".FindSolidBrush(),
							EmbeddedTreeStructure.Identity.Nonaligned => "PineTrail".FindSolidBrush(),
							EmbeddedTreeStructure.Identity.TreeNonaligned => "MistyFern".FindSolidBrush(),
							_ => "ElectricLime".FindSolidBrush()
						};
						return _Brush;
					}
				}
			}

			else if (MarkupType == MarkUpExteandType.Integer)
			{
				if (DisposeType == MarkUpDisposeType.Value)
				{
					if (AssistType == MarkUpAssistType.Multiplication)
					{
						if (value is string _string)
						{
							if (parameter is string _param &&
								int.TryParse(_string, out int _Count) &&
								int.TryParse(_param, out int _IntParam))
							{
								return _Count * _IntParam;
							}
						}
						else if (value is int _int)
						{
							if (parameter is string _param &&
								int.TryParse(_param, out int _IntParam))
							{
								return _int * _IntParam;
							}
						}
						else if (value is IEnumerable _Enumerable)
						{
							int count = 0;
							foreach (var i in _Enumerable)
							{
								count++;
							}
							if (parameter is string _param &&
								int.TryParse(_param, out int _IntParam))
							{
								return count * _IntParam;
							}
						}
					}
				}

                if (DisposeType == MarkUpDisposeType.Collection)
				{
					if (value is IEnumerable Collection)
					{
						int count = 0;
						foreach(var i in Collection)
						{
							count++;
						}
						return count;
					}
				}

            }

			else if (MarkupType == MarkUpExteandType.Rect)
			{
				if (DisposeType == MarkUpDisposeType.UIElement)
				{
					Logger.Print(RuntimeLog.LogType.Warning, "000 --", value);
					if (value is double ValidValus)
					{
						return new Rect(0, 0, ValidValus, ValidValus);
					}
				}
			}

			return DependencyProperty.UnsetValue;
        }

        private void CreaterInstance(UIBind Bind)
        {
			Application.Current.Dispatcher.InvokeAsync(() =>
			{
				async void Load(Interfacial interfacial)
				{
                    if (_InstanceMap.TryGetValue(interfacial, out Lazy<FrameworkElement>? LazyInfo))
                    {

                        LazyInfo.Value.Loaded += Loader;

                        void Loader(object sender, RoutedEventArgs e)
                        {
                            Bind.InstantiationCallBack?.Invoke();
                            LazyInfo.Value.Loaded -= Loader;
                        }

						if (Bind.IsPlayAnimation)
						{
							await Task.Delay(1300);
						}

						if (ControlElement != null) ControlElement.Content = LazyInfo.Value;
                    }
                }

				if (!_InstanceMap.ContainsKey(Bind.UIType))
				{
					if (UIBind.FactoryMap.TryGetValue(Bind.UIType, out Type? _Type))
					{
						object? _object = Activator.CreateInstance(_Type);
						if (_object is not null and FrameworkElement _FrameworkElement)
						{
							Lazy<FrameworkElement> NewFrameElement = new (_FrameworkElement);
							_InstanceMap[Bind.UIType] = NewFrameElement;
							Load(Bind.UIType);
                        }
					}
				}
				else
				{
					Load(Bind.UIType);
				}
            }, System.Windows.Threading.DispatcherPriority.Background);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value; ;
        }

        protected override Freezable CreateInstanceCore()
        {
			return base.CreateInstance();
        }
    }

    public class MarkupMultiConverter : DependencyObject, IMultiValueConverter
    {
        private readonly ILogger Logger = Log.ForContext<MarkupMultiConverter>();

        private readonly ConcurrentDictionary<Interfacial, Lazy<FrameworkElement>> _InstanceMap = [];

        public Brush Friendly { set; get; } = "JadeFlow".FindSolidBrush();

        public Brush Unamiable { set; get; } = "CoralRed".FindSolidBrush();

        public MarkUpExteandType MarkupType { set; get; } = MarkUpExteandType.Yield;

        public MarkUpDisposeType DisposeType { set; get; } = MarkUpDisposeType.Invalid;

        public MarkUpAssistType AssistType { set; get; } = MarkUpAssistType.Invalid;

        public object? Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (MarkupType == MarkUpExteandType.Yield)
			{
				if (values.Length == 2)
				{
					if (double.TryParse(values.ElementAt(0).GetSafetyChar(), out double _value1) &&
						double.TryParse(values.ElementAt(1).GetSafetyChar(), out double _value2))
					{
						double validValue = Math.Round(_value1 / (_value1 + _value2) * 100, 2);

						if (DisposeType == MarkUpDisposeType.AppendText && parameter is not null)
						{
							string AppendResult = string.Empty;

							if (AssistType == MarkUpAssistType.Left)
							{
                                return parameter.GetSafetyChar() + validValue.GetSafetyChar();
							}
							else if (AssistType == MarkUpAssistType.Right)
							{
                                return validValue.GetSafetyChar() + parameter.GetSafetyChar();
							}
                            else
                            {
                                if (parameter is string _format)
                                {
                                    return string.Format(_format.RepairstringFormat(), validValue);
                                }
                                else
                                {
                                    return parameter.GetSafetyChar() + validValue;
                                }
                            }
                        }
					}
				}
			}

			else if (MarkupType == MarkUpExteandType.Brush)
			{
				if (DisposeType == MarkUpDisposeType.Yield)
				{
					if (values.Length == 2)
					{
						if (double.TryParse(values.ElementAt(0).GetSafetyChar(), out double _value1) &&
							double.TryParse(values.ElementAt(1).GetSafetyChar(), out double _value2))
						{
							return _value1 / (_value1 + _value2) == 1.0 ? Friendly : Unamiable;
                        }
					}
				}
			}

			else if (MarkupType == MarkUpExteandType.Bool)
			{
				if (DisposeType == MarkUpDisposeType.Uniformity)
				{
					bool? _state = null;
					foreach (var _value in values)
					{
						if (bool.TryParse(values.ElementAt(0).GetSafetyChar(), out bool _bool))
						{
							if (_state == null)
							{
								_state = _bool;
							}
							else if (_state != _bool) return false;

						}
					}
					return _state ?? false;
				}
				else if (DisposeType == MarkUpDisposeType.ValidCheck)
				{
					bool MainBool = false;

					IEnumerable<object> Newvalue = [];

					if (AssistType == MarkUpAssistType.Left && values.First() is bool _left)
					{
						MainBool = _left;
						Newvalue = values.ToList().Skip(1);
					}
					else if (AssistType == MarkUpAssistType.Right && values.First() is bool _right)
					{
						MainBool = _right;
						Newvalue = values.ToList().Take(values.Length - 1);
					}

					bool? State = null;

					foreach (var item in Newvalue)
					{
						bool _TemState = item.IsAbsoluteValidValue();

						if (State is null)
						{
							State = _TemState;
						}
						else
						{
							if (State != _TemState)
							{
								State = false;
								break;
							}
						}
					}
					if (State is not null and bool _State)
					{
						if (!_State) MainBool = false;
					}

					return MainBool;
				}
			}

			else if (MarkupType == MarkUpExteandType.String)
			{
				if (DisposeType == MarkUpDisposeType.Contain && parameter is not null)
				{

					foreach (var _value in values)
					{
						if (_value is string _string && parameter is string _ConverterParameter)
						{
							if (_string.Contains(_ConverterParameter))
							{
								if (AssistType == MarkUpAssistType.PassBrush)
								{
									return Friendly;

								}
								else if (AssistType == MarkUpAssistType.FailBrush)
								{
									return Unamiable;
								}
							}
						}
					}
				}
				return Friendly;

			}

			else if (MarkupType == MarkUpExteandType.Addsub)
			{
				if (DisposeType == MarkUpDisposeType.GraduallyDecrease)
				{
					double TotalNum = 0;

					int index = 0;

					foreach (var value in values)
					{
						if (index == 0)
						{
                            if (value is double _actualwidth)
                            {
                                TotalNum = _actualwidth;
                            }
                            else if (value is Thickness _margin)
                            {
                                TotalNum = _margin.Left + _margin.Right;
                            }
                            else if (value is Thickness _border)
                            {
                                TotalNum = _border.Left + _border.Right;
                            }
                            else if (value is string _string &&
                                     double.TryParse(_string, out double _cvdouble))
							{
								TotalNum = _cvdouble;
                            }
                        }
						else
						{
							if (value is double _actualwidth)
							{
								TotalNum -= _actualwidth;
							}
							if (value is Thickness _margin)
							{
								TotalNum -= _margin.Left + _margin.Right;
							}
							if (value is Thickness _border)
							{
								TotalNum -= _border.Left + _border.Right;
							}
                            else if (value is string _string &&
                                     double.TryParse(_string, out double _cvdouble))
                            {
                                TotalNum -= _cvdouble;
                            }
                        }
						index++;
					}

					if (AssistType == MarkUpAssistType.MakeUpFor && double.TryParse(parameter?.GetSafetyChar(), out double _Supplement))
					{
						TotalNum -= _Supplement;
					}

					else if (AssistType == MarkUpAssistType.Lenght)
					{
						return new GridLength(TotalNum);
					}

					return TotalNum;
				}
				else if (DisposeType == MarkUpDisposeType.GraduallyIncrease)
				{
					double TotalNum = 0;

					foreach (var value in values)
					{
						if (value is double _actualwidth)
						{
							TotalNum += _actualwidth;
						}
						if (value is Thickness _margin)
						{
							TotalNum += _margin.Left + _margin.Right;
						}
						if (value is Thickness _border)
						{
							TotalNum += _border.Left + _border.Right;
						}
                        else if (value is string _string &&
                                double.TryParse(_string, out double _cvdouble))
                        {
                            TotalNum += _cvdouble;

                        }
                    }

					if (AssistType == MarkUpAssistType.MakeUpFor && double.TryParse(parameter?.GetSafetyChar(), out double _Supplement))
					{
						TotalNum += _Supplement;
					}
					return TotalNum;
				}
			}

            else if (MarkupType == MarkUpExteandType.MultiplyDivide)
            {
                double TotalNum = 1;
                //  *
                if (DisposeType == MarkUpDisposeType.Multiply)
                {
                    foreach (var value in values)
                    {
                        if (value is double _double)
                        {
                            TotalNum *= _double;
                        }
                        if (value is int _int)
                        {
                            TotalNum *= _int;
                        }
                        if (value is float _float)
                        {
                            TotalNum *= _float;
                        }
                    }
                    return TotalNum;
                }
				//  %
                else if (DisposeType == MarkUpDisposeType.Divide)
                {
					int index = 0;

                    foreach (var value in values)
                    {
						if (index == 0)
						{
                            if (value is double _double)
                            {
                                TotalNum = _double;
                            }
                            else if (value is int _int)
                            {
                                TotalNum = _int;
                            }
                            else if (value is float _float)
                            {
                                TotalNum = _float;
                            }
                            else if (value is string _string &&
                                     double.TryParse(_string, out double _cvdouble))
                            {
                                TotalNum = _cvdouble;

                            }
                        }
						else
						{
							if (value is double _double)
							{
								TotalNum /= _double;
							}
                            else if (value is int _int)
							{
								TotalNum /= _int;
							}
                            else if (value is float _float)
							{
								TotalNum /= _float;
							}
							else if (value is string _string &&
									 double.TryParse(_string, out double _cvdouble))
							{
								TotalNum /= _cvdouble;

                            }
						}
                        index++;
                    }
                   
                    return TotalNum;
                }
            }

            else if (MarkupType == MarkUpExteandType.Rect)
            {
                if (DisposeType == MarkUpDisposeType.UIElement)
                {
                    Logger.Print(RuntimeLog.LogType.Warning, "000 --", values.Select(x=>x.GetSafetyChar()).Join(" - "));
                    if (values.Length == 2 &&
						double.TryParse(values[0].GetSafetyChar(), out double width) &&
                        double.TryParse(values[1].GetSafetyChar(), out double height))
                    {
                        return new Rect(0, 0, width, height);
                    }
                }
            }

            return values.Select(x => x.GetSafetyChar()).Join(" ");
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            object[] result = new object[targetTypes.Length];

            for (var index = 0; index < targetTypes.Length; index++)
            {
                if (targetTypes[index].CanSafetyConvert(value) is not null and object _value)
                {
                    result[index] = _value;
                }
            }

            return result;
        }
    }
}